package com.hmy.contract.service.contract.create.lease;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hmy.ccp.common.result.FeignResult;
import com.hmy.contract.bo.request.oss.OssFileUploadRequest;
import com.hmy.contract.bo.response.oss.OssFileUploadResponse;
import com.hmy.contract.common.constant.ContractConstants;
import com.hmy.contract.common.utils.OssFilePathUtil;
import com.hmy.contract.commons.enums.ContractStatusEnum;
import com.hmy.contract.dal.mapper.ContractMapper;
import com.hmy.contract.dal.po.ContractPo;
import com.hmy.contract.manager.order.OrderFeignClientManager;
import com.hmy.contract.manager.signature.SignatureFeignClientManager;
import com.hmy.contract.service.contract.IContractService;
import com.hmy.contract.service.contract.create.IContractCreateService;
import com.hmy.contract.service.dto.contract.ContractRevokeDto;
import com.hmy.contract.service.dto.contract.FieldDto;
import com.hmy.contract.service.dto.contract.SignTaskDto;
import com.hmy.contract.service.oss.IOssService;
import com.hmy.contract.service.rdto.ContractActorDetailRdto;
import com.hmy.contract.service.rdto.ContractConfigRdto;
import com.hmy.contract.service.rdto.ContractRdto;
import com.hmy.contract.service.rdto.CreateContractRdto;
import com.hmy.infrastructure.api.bo.request.signature.*;
import com.hmy.infrastructure.api.bo.response.signature.CreateSignatureProcessApiResponse;
import com.hmy.infrastructure.api.bo.response.signature.GetSignFileUrlApiResponse;
import com.hmy.infrastructure.api.bo.response.signature.GetSignTaskUrlApiResponse;
import com.hmy.order.api.bo.request.ContractOrderStatusUpdateApiRequest;
import com.hmy.order.api.common.enums.OrderStatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author seven.qi 齐胜南
 * @version 1.0
 * @description
 * @date 2023/12/23 16:12
 */
@Service
@Slf4j
public class ElectronicLeaseContractCreateService implements IContractCreateService {

    @Value("${process.definition.id}")
    private String processDefinitionId;

    @Resource
    private SignatureFeignClientManager signatureFeignClientManager;

    @Resource
    private ContractMapper contractMapper;

    @Resource
    private IContractService contractService;

    @Resource
    private OrderFeignClientManager orderFeignClientManager;

    @Resource
    private IOssService ossService;

    @Override
    public String create(CreateContractRdto createContractDto) {
        CreateSignatureProcessApiRequest createSignatureProcessApiRequest = convertToRequest(createContractDto);
        FeignResult<CreateSignatureProcessApiResponse> createSignatureProcessApiResponseJsonResult = signatureFeignClientManager.create(createSignatureProcessApiRequest);
        return createSignatureProcessApiResponseJsonResult.getData().getSignTaskId();
    }

    private CreateSignatureProcessApiRequest convertToRequest(CreateContractRdto dto) {
        ContractConfigRdto configRdto = dto.getContractConfigRdto();
        CreateSignatureProcessApiRequest createSignatureProcessApiRequest = new CreateSignatureProcessApiRequest();
        createSignatureProcessApiRequest.setCreatorPhone(dto.getCreatorPhone());
        createSignatureProcessApiRequest.setSignTemplateId(dto.getSignTemplateId());
        createSignatureProcessApiRequest.setSealId(configRdto.getSealId());
        createSignatureProcessApiRequest.setBusinessId(configRdto.getBusinessId());
        createSignatureProcessApiRequest.setTaskSubject(dto.getTaskSubject());
        createSignatureProcessApiRequest.setTransReferenceId(String.valueOf(dto.getBusinessType()));
        Map<String, List<ContractActorDetailRdto>> actorMap = dto.getContractActorDetailList().stream().collect(Collectors.groupingBy(ContractActorDetailRdto::getActorType));
        ContractActorDetailRdto actorDetailRdto = actorMap.get(ContractConstants.PERSON).get(0);
        List<AuthorizerInfoApi> list = new ArrayList<>();
        AuthorizerInfoApi authorizerInfo = new AuthorizerInfoApi();
        authorizerInfo.setName(actorDetailRdto.getActorName());
        authorizerInfo.setPhone(actorDetailRdto.getAccountName());
        authorizerInfo.setIdCardNo(actorDetailRdto.getCertNoForMatch());
        list.add(authorizerInfo);
        createSignatureProcessApiRequest.setAuthorizerInfoList(list);
        return createSignatureProcessApiRequest;
    }

    @Override
    public List<FieldDto> fillFieldValue(CreateContractRdto createContractDto) {
        List<FieldDto> fieldList = new ArrayList<>();
        Map<String, Object> fieldMap = createContractDto.getFieldMap();
        for (String key : fieldMap.keySet()) {
            fieldList.add(FieldDto.builder().key(key).value(fieldMap.get(key).toString()).build());
        }
        return fieldList;
    }

    @Override
    public String start(String signTaskId, List<FieldDto> fieldDtoList, CreateContractRdto dto) {

        List<FieldApi> fieldApiList = BeanUtil.copyToList(fieldDtoList, FieldApi.class);

        SignTemplateFieldFillApiRequest signTemplateFieldFillApiRequest = new SignTemplateFieldFillApiRequest();
        signTemplateFieldFillApiRequest.setFieldList(fieldApiList);
        signTemplateFieldFillApiRequest.setSignTemplateId(dto.getSignTemplateId());
        signTemplateFieldFillApiRequest.setSignTaskId(signTaskId);
        signatureFeignClientManager.signTemplateFieldFill(signTemplateFieldFillApiRequest);


        StartSignatureProcessApiRequest startSignatureProcessApiRequest = new StartSignatureProcessApiRequest();
        startSignatureProcessApiRequest.setSignTaskId(signTaskId);
        signatureFeignClientManager.start(startSignatureProcessApiRequest);


        GetSignTaskUrlApiRequest getSignTaskUrlApiRequest = new GetSignTaskUrlApiRequest();
        getSignTaskUrlApiRequest.setSignTaskId(signTaskId);
        FeignResult<GetSignTaskUrlApiResponse> signTaskUrl = signatureFeignClientManager.getSignTaskUrl(getSignTaskUrlApiRequest);

        return signTaskUrl.getData().getSignTaskUrl();
    }

    @Override
    public void beforeCreate(CreateContractRdto dto) {

    }

    @Override
    public void afterCreate(CreateContractRdto dto) {
        ContractRdto contractRdto = dto.getContractRdto();
        ContractPo contractPo = new ContractPo();
        contractPo.setStatus(ContractStatusEnum.WAITING_SIGN.getStatus());
        contractPo.setContractTaskId(contractRdto.getContractTaskId());
        SignTaskDto signTaskDto = new SignTaskDto();
        signTaskDto.setContractSignTaskUrl(dto.getUrl());
        contractPo.setContractSignTaskUrl(JSONUtil.toJsonStr(signTaskDto));
        LambdaQueryWrapper<ContractPo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ContractPo::getContractId, contractRdto.getContractId());
        wrapper.eq(ContractPo::getIsDeleted, Boolean.FALSE);
        contractMapper.update(contractPo, wrapper);
    }

    @Override
    public Long notify(ContractRevokeDto dto) {
        Long contractId = contractService.contractInfoBySignTaskId(dto.getSignTaskId());
        ContractPo contractRo = contractService.getById(contractId);

        String path = "";

        try {
            path = saveSignedFile(contractRo);
        } catch (Exception e) {
            log.error("save signed file exception", e);
        }

        if (StrUtil.isNotEmpty(path)) {
            try {
                path = saveSignedFileToOss(path, contractRo.getContractNo());
            } catch (Exception e) {
                log.error("save signed file to oss exception", e);
            }
        }
        try {
            orderFeignClientManager.updateContractOrderStatus(new ContractOrderStatusUpdateApiRequest(contractRo.getOrderId(), OrderStatusEnum.SIGNED_EXAMINE.getOrderStatusCode()));
        } catch (Throwable throwable) {
            log.error("update order status exception", throwable);
        }
        LambdaQueryWrapper<ContractPo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ContractPo::getContractId, contractRo.getContractId());
        wrapper.eq(ContractPo::getIsDeleted, Boolean.FALSE);
        ContractPo contractPo = new ContractPo();
        contractPo.setStatus(ContractStatusEnum.SIGNED.getStatus());
        contractPo.setContractSignFileUrl(path);
        contractPo.setSignTime(LocalDateTime.now());
        contractPo.setUpdaterName("system");
        contractPo.setUpdateTime(LocalDateTime.now());
        contractService.update(contractPo, wrapper);
        return contractId;
    }

    private String saveSignedFileToOss(String path, String contractNo) {
        String storePath = OssFilePathUtil.createElectronicContractPath(contractNo);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        HttpUtil.download(path, outputStream, true);
        OssFileUploadRequest ossFileUploadRequest = new OssFileUploadRequest();
        ossFileUploadRequest.setInputStream(new ByteArrayInputStream(outputStream.toByteArray()));
        ossFileUploadRequest.setStorePath(storePath);
        OssFileUploadResponse res = ossService.ossFileUploadByStream(ossFileUploadRequest);
        return res.getOssPrefix();
    }

    private String saveSignedFile(ContractPo contractPo) {
        GetSignFileUrlApiRequest getSignFileUrlApiRequest = new GetSignFileUrlApiRequest();
        getSignFileUrlApiRequest.setSignTaskId(contractPo.getContractTaskId());
        FeignResult<GetSignFileUrlApiResponse> signFileUrl = signatureFeignClientManager.getSignFileUrl(getSignFileUrlApiRequest);
        return signFileUrl.getData().getSignFileUrl();
    }

}
